package activities;

import android.content.Context;
import android.content.Intent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.ToneGenerator;
import android.media.MediaPlayer.OnCompletionListener;
import android.net.Uri;
import android.os.CountDownTimer;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.TranslateAnimation;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.ViewFlipper;

import com.example.intellifit.R;
import com.google.android.gms.plus.PlusShare;

import org.achartengine.ChartFactory;
import org.achartengine.GraphicalView;

import activities.StatisticsActivity.ViewState;
import helper.Exercise;
import helper.ExercisesEnum;
import helper.GraphDataWrapper;
import helper.Settings;
import helper.SharedPreferencesHelper;
import helper.TimeSpan;
import simpleDB.DatabaseHelper;

public abstract class RepetitionsActivity extends FragmentActivity implements
		OnGestureListener, AnimationListener {

	/* --ANIMATION/SWIPE CONSTANTS */
	protected static final int SWIPE_MIN_DISTANCE = 100;
	protected static final int SWIPE_MAX_OFF_PATH = 250;
	protected static final int SWIPE_THRESHOLD_VELOCITY = 100;

	/* --SENSORS */
	protected SensorManager sManager;
	protected SensorEventListener thislistener;

	/* --VIEW COMPONENTS */
	protected ViewFlipper vf;
	protected TextView currReps;
	protected RelativeLayout overlay;
	protected LinearLayout overlayCountdown;
	protected LinearLayout overlayStopExercise;
	protected LinearLayout graph;
	protected ImageButton exerciseInfoBtn;
	protected GestureDetector gDetector;
	protected GraphicalView repetitionsChartView;

	/* --DATA FOR CURRENT EXCERCISE */
	// currentReps
	protected int repetitions = 0;
	// total reps
	protected int reps = 0;
	protected boolean started = false;
	protected ExercisesEnum exerciseType;
	protected Exercise currentExercise;
	protected ViewState currentViewState = ViewState.Day;
	protected TimeSpan currentTimeSpan = new TimeSpan(currentViewState);
	protected boolean db_uptoDate = false;
	protected DatabaseHelper dbHelper = new DatabaseHelper(this);
	protected GraphDataWrapper gdWrapper = new GraphDataWrapper(this,
			currentViewState, currentTimeSpan);
	protected Spinner spinner;
	private String[] viewSelection;
	protected long startTimeNS = 0;
	protected long endTimeNS = 0;

	// members for determing repetition accuracy
	protected long lastRepetitionTime = 0;
	protected long repetition_duratation = 2500;
	int executionAccuracy = 1;
	protected MediaPlayer mPlayer;

	/**
	 * sharedPreferences indicating whether splashscreen should be shown or not
	 */
	protected SharedPreferencesHelper spHelper;

	private boolean isBeeping = false;

	public void reInit() {
		overlayStopExercise.setVisibility(View.INVISIBLE);
		started = false;
		db_uptoDate = false;
		overlay.setVisibility(View.VISIBLE);

	}

	@Override
	public void onBackPressed() {
		// TODO Auto-generated method stub
		super.onBackPressed();
		started = false;
		updateDB();
	}

	protected void sayIt(int resId) {
		try {
			mPlayer = MediaPlayer.create(this, resId);
			mPlayer.setLooping(false);
			mPlayer.start();
			mPlayer.setOnCompletionListener(new OnCompletionListener() {
				public void onCompletion(MediaPlayer mp) {
					mPlayer.release();
				};
			});
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	protected void sayFaster() {
		sayIt(R.raw.faster);
	}

	protected void saySlower() {
		sayIt(R.raw.slower);
	}

	public abstract void registerListeners();

	protected void initLayoutComponents() {
		vf = (ViewFlipper) findViewById(R.id.vf);

		// init gui
		currReps = (TextView) findViewById(R.id.currRepetition);
		overlay = (RelativeLayout) findViewById(R.id.overlay);
		overlayCountdown = (LinearLayout) findViewById(R.id.overlayCountdown);
		overlayStopExercise = (LinearLayout) findViewById(R.id.overlayStopExercise);
		exerciseInfoBtn = (ImageButton) findViewById(R.id.showInfoBtn);

		exerciseInfoBtn.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				showExerciseInfo();
			}
		});

		overlay.setVisibility(View.VISIBLE);
	}

	protected void showExerciseInfo() {
		Intent i = new Intent(this, ExerciseInformationActivity.class);
		i.putExtra("ExerciseType", this.exerciseType);
		startActivityForResult(i, 2);
	}

	// Call Back method to get the Message form other Activity
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);

		// check if the request code is same as what is passed here it is 2
		if (requestCode == 2) {
			if (null != data) {
				// fetch the message String
				boolean showAgain = data.getBooleanExtra("showAgain", true);
				ExercisesEnum exType = (ExercisesEnum) data
						.getSerializableExtra("ExerciseType");

				if (spHelper != null) {
					spHelper.savePrefsShowExAgain(exType, showAgain);
				}

			}
		}
	}

	protected void createStatisticOverlay(boolean update) {
		vf.setDisplayedChild(1);
		db_uptoDate = false;
		TextView tf = (TextView) findViewById(R.id.titleToAdd);
		tf.setText("exercise stopped - " + currentExercise.getName());
		ExcerciseStoppedBtnListener blistener = new ExcerciseStoppedBtnListener();
		Button continueBtn = (Button) findViewById(R.id.continueExBtn);
		Button seeStatsBtn = (Button) findViewById(R.id.seeStatsBtn);
		Button finishBtn = (Button) findViewById(R.id.finishBtn);
		Button todayBtn = (Button) findViewById(R.id.todayBtn);

		if (Settings.DISPLAY_HEIGHT <= 800) {
			continueBtn.setTextSize(13);
			seeStatsBtn.setTextSize(13);
			finishBtn.setTextSize(13);
			((Button) findViewById(R.id.shareBtn)).setTextSize(13);
		}

		continueBtn.setOnClickListener(blistener);
		seeStatsBtn.setOnClickListener(blistener);
		finishBtn.setOnClickListener(blistener);
		todayBtn.setOnClickListener(blistener);
		if (!update) {
			if (spinner == null) {

				spinner = (Spinner) findViewById(R.id.changeViewSpinnerBtn);
				ArrayAdapter<CharSequence> adapter = ArrayAdapter
						.createFromResource(this,
								R.array.statistics_view_state,
								android.R.layout.simple_spinner_item);

				adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
				spinner.setAdapter(adapter);

				spinner.setOnItemSelectedListener(new OnItemSelectedListener() {

					public void onItemSelected(AdapterView<?> arg0, View arg1,
							int arg2, long arg3) {

						// storing string resources into Array
						viewSelection = getResources().getStringArray(
								R.array.statistics_view_state);
						updateViewState();

					}

					public void onNothingSelected(AdapterView<?> arg0) {
						// do nothing

					}

				});
			}
		}

		// overlayStatistics = (LinearLayout)
		// findViewById(R.id.overlayStatistics);
		//
		// overlayStatistics.setVisibility(View.VISIBLE);

		graph = (LinearLayout) findViewById(R.id.chart);

		graph.removeAllViews();
		// TODO replace static values with dynamically
		gdWrapper.updateSingleDataset(this.currentExercise.getId(), 1,
				currentViewState, currentTimeSpan,
				this.currentExercise.getName());
		gdWrapper.updateSingleRendererStyling();

		gdWrapper.setColor(this.currentExercise.getName());

		repetitionsChartView = ChartFactory.getBarChartView(
				getApplicationContext(), gdWrapper.getDataset(),
				gdWrapper.getRenderer(),
				org.achartengine.chart.BarChart.Type.DEFAULT);

		graph.addView(repetitionsChartView, new LayoutParams(
				LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));

		Button shareButton = (Button) findViewById(R.id.shareBtn);
		shareButton.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				// Launch the Google+ share dialog with attribution to your app.
				Intent shareIntent = new PlusShare.Builder(
						getApplicationContext())
						.setType("text/plain")
						.setText(
								"I have just completed " + reps
										+ " repetitions of " + exerciseType
										+ " with intelliFit!").getIntent();

				startActivityForResult(shareIntent, 0);
			}
		});

	}

	public void updateViewState() {
		int pos = spinner.getSelectedItemPosition();

		if (viewSelection[pos].toLowerCase().equals("year")) {
			this.currentViewState = ViewState.Month;

		} else if (viewSelection[pos].toLowerCase().equals("week")) {
			this.currentViewState = ViewState.Day;

		}
		createStatisticOverlay(true);
	}

	protected void updateDB() {
		long duration = (long) endTimeNS - (long) startTimeNS;
		duration = duration / (long) 1000000;
		if (duration > 0) {
			spHelper.savePrefsExTime(this.exerciseType, duration);
		}

		// datum
		// excercise-ID
		// nr of reps
		Log.i("GMM", "ID bei write: " + currentExercise.getId());
		dbHelper.addRepetitions(Settings.getInstance().getPersonID(),
				currentTimeSpan.getDateAsString(currentTimeSpan.today),
				currentExercise.getId(), repetitions, executionAccuracy,
				(int) duration);
		// TODO add real not random accuracy rate to DB
		if (repetitions > 0) {
			double tmp = Math.round((executionAccuracy / repetitions));
			Log.i("GMM", "REPS done: " + repetitions + "; execution ok: " + tmp
					* 100 + "%");
		}
		db_uptoDate = true;
	}

	protected void updateCurrRepsView(int reps) {
		playBeepSound(this, 1);
		currReps.setText(Integer.toString(reps));
	}

	/**
	 * Plays beep sounds using MediaPlayer class.
	 * 
	 * @param c
	 * @param i
	 */
	protected void playBeepSound(Context c, int i) {
		if (isBeeping)
			return;

		isBeeping = true;
		try {
			final ToneGenerator tg = new ToneGenerator(
					AudioManager.STREAM_NOTIFICATION, 100);
			if (i == 0) {
				tg.startTone(ToneGenerator.TONE_PROP_BEEP);
			} else {
				tg.startTone(ToneGenerator.TONE_PROP_PROMPT);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		isBeeping = false;
	}

	/**
	 * Initiates the countdown for the current excercise.
	 */
	protected void startCountDown() {

		overlay.setVisibility(View.INVISIBLE);
		overlayCountdown.setVisibility(View.VISIBLE);

		new CountDownTimer(5000, 1000) {
			TextView tv = (TextView) findViewById(R.id.countdownTV);

			public void onTick(long millisUntilFinished) {

				if ((millisUntilFinished / 1000) <= 1) {
					playBeepSound(getApplicationContext(), 1);
					tv.setText("go!");

					started = true;
				} else {
					playBeepSound(getApplicationContext(), 0);
					tv.setText(String.valueOf((millisUntilFinished / 1000) - 1));

				}
			}

			public void onFinish() {
				overlayCountdown.setVisibility(View.INVISIBLE);
				findViewById(R.id.overlayStopExercise).setVisibility(
						View.VISIBLE);
				startTimeNS = System.nanoTime();

			}
		}.start();

	}

	@Override
	public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
			float velocityY) {

		Log.i("FLING", "-Fling! -");

		if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH)
			return false;

		// right to left swipe
		if (e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE
				&& Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
			Log.i("SWIPE_DET", "RIGHT-->LEFT");
			TranslateAnimation animate = new TranslateAnimation(0,
					-graph.getWidth(), 0, 0);
			animate.setDuration(500);
			animate.setAnimationListener(this);
			// animate.setFillAfter(true);
			this.currentTimeSpan.increaseTimeSpan(currentViewState);
			graph.startAnimation(animate);
			((Button) findViewById(R.id.todayBtn)).startAnimation(animate);
			repetitionsChartView = null;

		} else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE
				&& Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
			Log.i("SWIPE_DET", "LEFT->RIGHT");
			TranslateAnimation animate = new TranslateAnimation(0,
					graph.getWidth(), 0, 0);
			animate.setDuration(500);
			animate.setAnimationListener(this);
			// animate.setFillAfter(true);
			this.currentTimeSpan.decreaseTimeSpan(currentViewState);
			graph.startAnimation(animate);
			((Button) findViewById(R.id.todayBtn)).startAnimation(animate);
			repetitionsChartView = null;

		}

		return true;
	}

	private class ExcerciseStoppedBtnListener implements OnClickListener {

		@Override
		public void onClick(View v) {
			if (v.getId() == R.id.continueExBtn) {
				vf.setDisplayedChild(0);
				reInit();
			} else if (v.getId() == R.id.finishBtn) {
				finish();
			} else if (v.getId() == R.id.seeStatsBtn) {
				Intent n = new Intent(v.getContext(), StatisticsActivity2.class);
				n.putExtra("exercise_data", currentExercise);
				startActivityForResult(n,4711);
			} else if (v.getId() == R.id.todayBtn) {
				currentTimeSpan = new TimeSpan(currentViewState);
				createStatisticOverlay(true);
			}

		}

	}

	@Override
	public boolean onDown(MotionEvent e) {
		return false;
	}

	@Override
	public void onLongPress(MotionEvent e) {

	}

	@Override
	public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
			float distanceY) {

		return false;
	}

	@Override
	public void onShowPress(MotionEvent e) {

	}

	@Override
	public boolean onSingleTapUp(MotionEvent e) {

		return false;
	}

	@Override
	public boolean dispatchTouchEvent(MotionEvent ev) {
		super.dispatchTouchEvent(ev);
		return gDetector.onTouchEvent(ev);
	}

	@Override
	public void onAnimationEnd(Animation animation) {
		createStatisticOverlay(false);
	}

	@Override
	public void onAnimationRepeat(Animation animation) {

	}

	@Override
	public void onAnimationStart(Animation animation) {

	}

}
